#include <bits/stdc++.h>
// 2025/05/17
// tag: Persistent segment tree
// Author: Forever
using namespace std;
using int64 = int64_t;

#define MAXN 100001
#define LOG_MAX 20

class PST {
private:
    class Segmenttree {
    public:
        int lc, rc, sum;
    };
    Segmenttree tr[MAXN * 32];
    int idx, now, len, root[MAXN];
    /**
     * @brief 递归构建线段树
     *
     * 该函数用于递归构建线段树，为每个节点分配唯一编号，初始化节点的和，
     * 并根据区间范围递归构建左右子树。
     *
     * @param l 当前构建区间的左端点
     * @param r 当前构建区间的右端点
     * @return int 新构建节点的编号
     */
    int build(int l, int r)
    {
        int x = ++idx; // 分配一个新的节点编号
        tr[x].sum = 0; // 初始化该节点的和为 0
        if (l == r) // 若当前区间只有一个元素，即到达叶子节点
            return x; // 返回当前节点的编号
        int mid = (l + r) >> 1; // 计算区间的中点
        // 递归构建左子树和右子树，并将它们的根节点编号分别赋值给当前节点的左右子节点
        tr[x].lc = build(l, mid), tr[x].rc = build(mid + 1, r);
        return x; // 返回当前节点的编号
    }
    /**
     * @brief 向可持久化线段树中插入元素
     *
     * 该函数用于在可持久化线段树中插入元素，创建新版本的线段树。
     * 复制当前节点，根据插入位置递归更新左右子树，最后更新节点的和。
     *
     * @param cur 当前节点的编号
     * @param l 当前区间的左端点
     * @param r 当前区间的右端点
     * @param x 要插入元素的位置
     * @param s 要插入元素的值
     * @return int 新节点的编号
     */
    int insert(int cur, int l, int r, int x, int s)
    {
        int k = ++idx; // 分配一个新的节点编号
        tr[k] = tr[cur]; // 复制当前节点的信息到新节点
        if (l == r) { // 若当前区间只有一个元素，即到达叶子节点
            tr[k].sum += s; // 更新叶子节点的和
            return k; // 返回新节点的编号
        }
        int mid = (l + r) >> 1; // 计算区间的中点
        if (x <= mid) // 若插入位置在左半区间
            tr[k].lc = insert(tr[k].lc, l, mid, x, s); // 递归更新左子树
        else // 若插入位置在右半区间
            tr[k].rc = insert(tr[k].rc, mid + 1, r, x, s); // 递归更新右子树
        // 更新当前节点的和，为左右子树节点和之和
        tr[k].sum = tr[tr[k].lc].sum + tr[tr[k].rc].sum;
        return k; // 返回新节点的编号
    }
    /**
     * @brief 在可持久化线段树中查询第 k 小的元素
     *
     * 该函数用于在可持久化线段树中查询第 k 小的元素。
     * 通过比较左右子树节点和，递归地在左右子树中查找第 k 小的元素。
     *
     * @param a 第一个版本线段树的节点编号
     * @param b 第二个版本线段树的节点编号
     * @param c 第三个版本线段树的节点编号
     * @param d 第四个版本线段树的节点编号
     * @param l 当前区间的左端点
     * @param r 当前区间的右端点
     * @param k 要查询的第 k 小元素
     * @return int 第 k 小元素所在的位置
     */
    int query(int a, int b, int c, int d, int l, int r, int k)
    {
        // 若当前区间只有一个元素，说明找到了第 k 小的元素，直接返回该元素的位置
        if (l == r)
            return l;
        // 计算区间中点
        int mid = (l + r) >> 1;
        // 计算左子树中元素的数量，通过四个版本线段树左子树节点和的差值得到
        int opt = tr[tr[a].lc].sum + tr[tr[b].lc].sum - tr[tr[c].lc].sum - tr[tr[d].lc].sum;
        // 若第 k 小的元素在左子树中
        if (k <= opt)
            // 递归查询左子树
            return query(tr[a].lc, tr[b].lc, tr[c].lc, tr[d].lc, l, mid, k);
        else
            // 若第 k 小的元素在右子树中，更新 k 的值（减去左子树元素数量），并递归查询右子树
            return query(tr[a].rc, tr[b].rc, tr[c].rc, tr[d].rc, mid + 1, r, k - opt);
    }

public:
    PST(int l)
    {
        idx = 0, len = l;
        build(1, len);
    }
    int insert(int cur, int x, int s)
    {
        return insert(cur, 1, len, x, s);
    }
    int query(int a, int b, int c, int d, int k)
    {
        return query(a, b, c, d, 1, len, k);
    }
};

int n, m, len, a[MAXN], ind[MAXN], id[MAXN], id2[MAXN];
vector<int> tree[MAXN];

int up[MAXN][LOG_MAX];
int depth[MAXN];

/**
 * @brief 预处理节点的祖先信息和深度信息
 *
 * 该函数使用深度优先搜索（DFS）递归地预处理每个节点的倍增祖先数组 up 和深度数组 depth。
 * 倍增祖先数组 up 用于快速查找节点的第 2^k 个祖先，深度数组 depth 记录每个节点的深度。
 *
 * @param u 当前正在处理的节点
 * @param parent 当前节点的父节点
 */
void preprocess(int u, int parent)
{
    // 初始化当前节点 u 的第 2^0 = 1 个祖先为其父节点
    up[u][0] = parent;
    // 计算当前节点 u 的第 2^k 个祖先，使用倍增思想
    for (int k = 1; k < LOG_MAX; ++k) {
        // 当前节点 u 的第 2^k 个祖先是其第 2^(k-1) 个祖先的第 2^(k-1) 个祖先
        up[u][k] = up[up[u][k - 1]][k - 1];
    }
    // 遍历当前节点 u 的所有子节点
    for (int v : tree[u]) {
        // 避免重复处理父节点
        if (v != parent) {
            // 子节点 v 的深度为其父节点 u 的深度加 1
            depth[v] = depth[u] + 1;
            // 递归处理子节点 v
            preprocess(v, u);
        }
    }
}

void dfs(PST& rt, int u, int parent)
{
    id[u] = rt.insert(id[parent], lower_bound(ind + 1, ind + len + 1, a[u]) - ind, 1);
    for (int v : tree[u])
        if (v != parent)
            dfs(rt, v, u);
}

/**
 * @brief 使用倍增算法计算两个节点的最近公共祖先（Lowest Common Ancestor, LCA）
 *
 * 该函数通过倍增算法找出树中两个节点 u 和 v 的最近公共祖先。
 * 首先将深度较深的节点提升到与另一个节点相同的深度，然后同步向上跳跃，
 * 直到找到最近公共祖先。
 *
 * @param u 第一个节点
 * @param v 第二个节点
 * @return int 节点 u 和 v 的最近公共祖先的编号
 */
int lca(int u, int v)
{
    // 确保 u 是深度较深的节点，方便后续操作
    if (depth[u] < depth[v])
        swap(u, v);
    // 第一步：将节点 u 提升到与节点 v 相同的深度
    for (int k = LOG_MAX - 1; k >= 0; --k) {
        // 若 u 向上跳跃 2^k 步后，其深度仍不小于 v 的深度，则进行跳跃
        if (depth[u] - (1 << k) >= depth[v]) {
            u = up[u][k]; // u 向上跳跃 2^k 步
        }
    }
    // 若 u 和 v 已经相等，说明 v 就是它们的最近公共祖先
    if (u == v)
        return u;
    // 第二步：同步向上跳跃，找到最近公共祖先的子节点
    for (int k = LOG_MAX - 1; k >= 0; --k) {
        // 若 u 和 v 向上跳跃 2^k 步后不是同一个节点，则进行跳跃
        if (up[u][k] != up[v][k]) {
            u = up[u][k]; // u 向上跳跃 2^k 步
            v = up[v][k]; // v 向上跳跃 2^k 步
        }
    }
    // 此时 u 和 v 的父节点就是最近公共祖先
    return up[u][0];
}

/**
 * @brief 主函数，程序的入口点
 *
 * 该函数负责读取输入数据，初始化可持久化线段树，预处理节点信息，
 * 并进行多次查询操作，输出每次查询的第 k 小元素。
 *
 * @return int 程序退出状态码，0 表示正常退出
 */
signed main()
{
    // 读取节点数量 n 和查询次数 m
    cin >> n >> m;
    // 读取每个节点的值
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    // 读取树的边信息，构建无向图
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        tree[u].push_back(v);
        tree[v].push_back(u);
    }
    // 预处理节点的祖先信息和深度信息，根节点为 1
    preprocess(1, 1);
    // 复制节点值数组 a 到 ind 数组，用于离散化处理
    memcpy(ind, a, sizeof(ind));
    // 对 ind 数组进行排序
    sort(ind + 1, ind + n + 1);
    // 对 ind 数组去重，并计算去重后的元素数量
    len = unique(ind + 1, ind + n + 1) - ind - 1;
    // 创建可持久化线段树对象，传入去重后的元素数量
    PST rt(len);
    // 初始化根节点的线段树版本，插入值为 0 的元素
    id[0] = rt.insert(1, 0, 0);
    // 深度优先搜索，构建每个节点对应的线段树版本
    dfs(rt, 1, 1);
    // 用于记录上一次查询的结果，初始化为 0
    unsigned int last = 0;
    // 进行 m 次查询
    for (int i = 1; i <= m; i++) {
        unsigned int l, r, k;
        // 读取查询的两个节点 l 和 r，以及第 k 小元素的 k 值
        cin >> l >> r >> k;
        // 对查询的节点 l 进行异或操作，使用上一次查询的结果
        l ^= last;
        // 计算节点 l 和 r 的最近公共祖先
        int lca_node = lca(l, r);
        // 在可持久化线段树中查询第 k 小元素，并通过 ind 数组映射回原始值
        last = ind[rt.query(id[l], id[r], id[lca_node], id[up[lca_node][0]], k)];
        // 输出本次查询的结果
        cout << last << endl;
    }
    return 0;
}